package com.kn.keywordmatch.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONUtil;
import com.kn.keywordmatch.common.IndexRotator;
import com.kn.keywordmatch.common.MediaTypeEnum;
import com.kn.keywordmatch.common.RabbitMqCon;
import com.kn.keywordmatch.common.RedisKey;
import com.kn.keywordmatch.dto.req.*;
import com.kn.keywordmatch.dto.resp.BaseResp;
import com.kn.keywordmatch.dto.resp.MatchDistanceResp;
import com.kn.keywordmatch.dto.resp.PlanManagesItem;
import com.kn.keywordmatch.dto.resp.PlanResp;
import com.kn.keywordmatch.service.DirectionKeywordIndex;
import com.kn.keywordmatch.service.KeywordIndex;
import com.kn.keywordmatch.service.PlanService;
import lombok.extern.slf4j.Slf4j;
import org.ahocorasick.trie.Emit;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@Slf4j
public class PlanServiceImpl implements PlanService {

    private static Object SQLOutput;
    @Autowired
    @Qualifier("redisTemplateWithString")
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private DirectionKeywordIndex directionKeywordIndex;
    @Autowired
    private KeywordIndex keywordIndex;

    IndexRotator indexRotator = new IndexRotator(Arrays.asList(0,1,2,3,4));


//    @Autowired
//    public PlanServiceImpl(DirectionKeywordIndex directionKeywordIndex,KeywordIndex keywordIndex) {
//        this.directionKeywordIndex = directionKeywordIndex;
//        this.keywordIndex = keywordIndex;
//    }

    final double distance = 100.0;

    @Override
    public List<MatchDistanceResp> matchDistance(List<MatchDistanceReq> reqList) {
        List<MatchDistanceResp> respList = new ArrayList<>();
        // 定义批次大小
        int batchSize = 10;
        for (int i = 0; i < reqList.size(); i += batchSize) {
            int end = Math.min(i + batchSize, reqList.size());
            List<MatchDistanceReq> batchReqList = reqList.subList(i, end);
            List<MatchDistanceResp> batchRespList = new ArrayList<>();
            for (MatchDistanceReq req : batchReqList) {
                if(Objects.nonNull(req.getLongitude()) && Objects.nonNull(req.getLatitude())){
                    // 从 Redis 获取符合距离的数据
                    List<PlanResp> filterPlanList = getPlanRespInBatches(RedisKey.MONITOR_LOCAL_REDIS_KEY,req.getLongitude(),req.getLatitude());
                    // 匹配逻辑
                    buildResp(batchRespList, req, filterPlanList);
                }
            }
            if(!batchRespList.isEmpty()){
                respList.addAll(batchRespList);
            }
        }
        return respList;
    }

    private List<MatchDistanceResp> sendPushMsg(List<MatchDistanceReq> reqList, List<MatchDistanceResp> respList, String s) {
        if (!respList.isEmpty()) {
            log.info(s, reqList.stream().map(MatchDistanceReq::getDataID).collect(Collectors.toList()));

            // 匹配完成后发给推送队列
            String messageId = UUID.randomUUID().toString();
            Message pushDataMessage = MessageBuilder.withBody(JSONUtil.toJsonStr(respList).getBytes(StandardCharsets.UTF_8))
                    .setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN)
                    .setMessageId(messageId)  // 设置 MessageId
                    .setDeliveryMode(MessageDeliveryMode.PERSISTENT)
                    .build();
            CorrelationData correlationData = new CorrelationData(messageId);
            rabbitTemplate.send(RabbitMqCon.DIRECT_EXCHANGE, RabbitMqCon.PUSH_MATCHED_DATA_KEY, pushDataMessage, correlationData);
        }
        return respList;
    }

    @Override
    public List<MatchDistanceResp> matchPoleDistance(List<MatchDistanceReq> reqList) {
        List<MatchDistanceResp> respList = new ArrayList<>();
        // 定义批次大小
        int batchSize = 10;
        // 将 reqList 分批处理
        for (int i = 0; i < reqList.size(); i += batchSize) {
            int end = Math.min(i + batchSize, reqList.size());
            List<MatchDistanceReq> batchReqList = reqList.subList(i, end);

            List<MatchDistanceResp> batchRespList = new ArrayList<>();
            for (MatchDistanceReq req : batchReqList) {
                if(Objects.nonNull(req.getLongitude()) && Objects.nonNull(req.getLatitude())){
                    // 从 Redis 获取符合距离的数据
                    List<PlanResp> filterPlanList = getPlanRespInBatches(RedisKey.POLE_MONITOR_LOCAL_REDIS_KEY,req.getLongitude(),req.getLatitude());
                    // 构建返回参数
                    buildResp(batchRespList, req, filterPlanList);
                }
            }
            if(!batchRespList.isEmpty()){
                respList.addAll(batchRespList);
            }
        }

        return respList;
    }



    private void buildResp(List<MatchDistanceResp> respList, MatchDistanceReq req, List<PlanResp> filterPlanList) {
        MatchDistanceResp buildResp = new MatchDistanceResp();
        buildResp(buildResp,req);
        List<PlanManagesItem> planManages = new ArrayList<>();
        buildResp.setLongitude(req.getLongitude());
        buildResp.setLatitude(req.getLatitude());
        buildResp.setLocationId(req.getLocationId());
        if(filterPlanList.isEmpty()){
            return;
        }else {
            for (PlanResp planResp : filterPlanList) {
                PlanManagesItem planManagesItem = new PlanManagesItem();
                planManagesItem.setPlanManageId(planResp.getPlanID());
                planManagesItem.setMonitorType(2);
                planManagesItem.setAgencyId(planResp.getAgencyId());
                planManages.add(planManagesItem);
            }
        }
        buildResp.setPlanManages(planManages);
        respList.add(buildResp);
    }


    private static final Pattern LOCATION_PATTERN = Pattern.compile("定位[：:](.{2,70})");

    private MatchDistanceResp buildResp(MatchDistanceResp matchDistanceResp, MatchDistanceReq req) {
        matchDistanceResp.setAuthor
                (req.getAuthor());
        matchDistanceResp.setDataID(req.getDataID());
        if(StrUtil.isNotBlank(req.getContent())){
            String content = req.getContent();
            try {
                int index = content.indexOf("定位");
                // 从内容中提取定位
                if (index != -1) {
                    // 截取定位附近的文本
                    String subContent = content.substring(index, Math.min(index + 100, content.length()));
                    Matcher matcher = LOCATION_PATTERN.matcher(subContent);
                    if (matcher.find()) {
                        String location = matcher.group(1);
                        matchDistanceResp.setLocation(location);
                    }
                }
            }catch (Exception e){
                log.error("定位匹配异常：{}",JSONUtil.toJsonStr(content));
            }
        }
        if (StrUtil.isNotBlank(req.getImageContent())) {
            matchDistanceResp.setContent(req.getContent() + "图片内容:" + req.getImageContent());
        }else {
            matchDistanceResp.setContent(req.getContent());
        }
        matchDistanceResp.setMediaLink(req.getMediaType());

        matchDistanceResp.setMediaType(0);
        if(StrUtil.isNotBlank(req.getPublishTime())){
            matchDistanceResp.setReleaseTime(req.getPublishTime().replace("T"," "));
        }
        matchDistanceResp.setSource(req.getSource());
        matchDistanceResp.setLongitude(req.getLongitude());
        matchDistanceResp.setLatitude(req.getLatitude());
        matchDistanceResp.setTitle(req.getTitle());
        matchDistanceResp.setWebsite(req.getSourceUrl());
        matchDistanceResp.setCoverPhoto(req.getVideoImage());
        matchDistanceResp.setVideoPath(req.getVideoUrl());
        matchDistanceResp.setNickname(req.getSourceSite());
        matchDistanceResp.setStickerID(req.getStickerID());

        return matchDistanceResp;
    }

//    public static void main(String[] args) {
//        String content = "来承瑞35天吨\n定位:辽宁省”江阳市一白塔区-浙延大街与东顺城路交叉口西南228米一#香庭院";
//        try {
//            int index = content.indexOf("定位");
//            // 从内容中提取定位
//            if (index != -1) {
//                // 截取定位附近的文本
//                String subContent = content.substring(index, Math.min(index + 100, content.length()));
//                Matcher matcher = LOCATION_PATTERN.matcher(subContent);
//                if (matcher.find()) {
//                    String location = matcher.group(1);
//                    System.out.println(location);                }
//            }
//        }catch (Exception e){
//            log.info("定位匹配失败");
//        }
//    }

    public List<PlanResp> getPlanRespInBatches(String redisKey, double longitude, double latitude) {
        // 使用 Redis GEO 查询范围内的点, 默认100km的点
        GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo()
                .radius(redisKey+ ":GPS", new Circle(new Point(longitude, latitude), new Distance(distance, Metrics.KILOMETERS)));

        List<PlanResp> resultList = new ArrayList<>();
        if (results != null) {
            for (GeoResult<RedisGeoCommands.GeoLocation<String>> result : results) {
                String planID = result.getContent().getName();
                PlanResp planResp = getPlanRespById(redisKey,planID);
                if (planResp != null) {
                    // 使用 PlanResp 自带的距离来判断是否在查询点的范围内
                    double distanceToPoint = calculateDistance(latitude, longitude, planResp.getLatitude(), planResp.getLongitude());
                    if (distanceToPoint <= planResp.getDistance()) {
                        resultList.add(planResp);
                    }
                }
            }
        }
        return resultList;
    }
    private PlanResp getPlanRespById(String redisKey,String planID) {
        String planRespJson = (String) redisTemplate.opsForHash().get(redisKey + ":hash", String.valueOf(planID));
        if (planRespJson != null) {
            return JSONUtil.toBean(planRespJson, PlanResp.class);
        }
        return null;
    }
    // 计算两点之间的距离
    private double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
        final int R = 6371; // 地球半径，单位为公里
        double latDistance = Math.toRadians(lat2 - lat1);
        double lonDistance = Math.toRadians(lon2 - lon1);
        double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
                + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
                * Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return R * c * 1000; // 转换为米
    }


    // 定向匹配
    @Override
    public List<MatchDistanceResp> matchByDirection(List<MatchDistanceReq> reqList) {

        List<MatchDistanceResp> respList = new ArrayList<>();
        // 定义批次大小
        int batchSize = 10;
        // 过滤公众号的数据
        // 将 reqList 分批处理
        reqList = reqList.stream().filter(r -> MediaTypeEnum.WECHAT_ACCOUNT.getCode().equals(r.getMediaType())).collect(Collectors.toList());
        if (CollUtil.isEmpty(reqList)) {
            log.info("定向过滤公众号数据为空");
            return new ArrayList<>();
        }
        for (int i = 0; i < reqList.size(); i += batchSize) {
            int end = Math.min(i + batchSize, reqList.size());
            List<MatchDistanceReq> batchReqList = reqList.subList(i, end);
            // 提交并行任务
            List<MatchDistanceResp> responseList = new ArrayList<>();
            for (MatchDistanceReq req : batchReqList) {
                MatchDistanceResp matchDistanceResp = BeanUtil.copyProperties(req, MatchDistanceResp.class);

                String author = req.getAuthor().trim();
                String source = req.getSource().trim();
                // 在 Trie 中查找匹配的关键字
                String text = author + " " + source;
                List<Emit> authorMatches = new ArrayList<>();
                if(StrUtil.isNotBlank(text)){
                    authorMatches = directionKeywordIndex.match(text);
                }
                if(authorMatches.isEmpty()){
                    continue;
                }
                // 使用 Set 来存储匹配的计划 ID，以去重
                Set<String> matchedPlanIDs = new HashSet<>();

                // 从倒排索引中查找与 author 匹配的计划 ID
                for (Emit emit : authorMatches) {
                    matchedPlanIDs.addAll(directionKeywordIndex.getPlansByKeyword(emit.getKeyword()));
                }

                // 使用 hMGet 一次性获取多个 JSON 字符串
                List<Object> jsonStrList = redisTemplate.opsForHash().multiGet(RedisKey.MONITOR_DIRECTION_REDIS_KEY,
                        matchedPlanIDs.stream()
                                .map(String::valueOf)
                                .collect(Collectors.toList()));

                // 反序列化每个 JSON 字符串为 MatchByDirectionReq 对象
                List<MatchByDirectionReq> redisList = new ArrayList<>();

                for (Object jsonStr : jsonStrList) {
                    if (jsonStr != null) {
                        redisList.add(JSONUtil.toBean((String) jsonStr, MatchByDirectionReq.class));
                    }
                }
                // 构建响应
                List<PlanManagesItem> managesItemList = new ArrayList<>();
                if(CollUtil.isNotEmpty(redisList)){
                    // 再次遍历 redisList，将没有重复的项加入 managesItemList
                    for (MatchByDirectionReq matchByDirectionReq : redisList) {
                        if (matchByDirectionReq != null) {
                            for (MatchDirectItem matchDirectItem : matchByDirectionReq.getDirectList()) {
                                if (matchDirectItem.getAccountName().trim().equals(req.getAuthor()) || matchDirectItem.getAccountName().trim().equals(req.getSource())) {
                                    PlanManagesItem planManagesItem = createPlanManagesItem(matchByDirectionReq, matchDirectItem);
                                    // 构建 uniqueKey
                                    String keyword = planManagesItem.getKeyword();
                                    String sourceUrl = req.getSourceUrl();
                                    String uniqueKey = planManagesItem.getPlanManageId() + "|" + keyword + "|" + sourceUrl;
                                    String uniqueKeyHash = DigestUtil.md5Hex16(uniqueKey);
                                    // 通过 Redis 判断是否重复 不存在则返回
                                    if (redisTemplate.opsForSet().isMember(RedisKey.DIRECTION_REPEAT_REDIS_KEY, uniqueKeyHash) == Boolean.FALSE) {
                                        managesItemList.add(planManagesItem);
                                    }else {
                                        log.info("定向匹配去重：{}",uniqueKey);
                                    }
                                }
                            }
                        }
                    }
                }

                if(!managesItemList.isEmpty()){
                    // 异步存储本次的值
                    saveRedis(req, redisList,RedisKey.DIRECTION_REPEAT_REDIS_KEY);
                    buildResp(matchDistanceResp, req);
                    matchDistanceResp.setPlanManages(managesItemList);
                    responseList.add(matchDistanceResp);
                }
            }
            if(!responseList.isEmpty()){
                respList.addAll(responseList);
            }
        }
        return respList;

    }

    private void saveRedis(MatchDistanceReq req, List<MatchByDirectionReq> redisList,String Key) {
        // 构建批量操作的 Pipeline
        redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            // Redis 的键名
            byte[] redisKey =Key.getBytes(StandardCharsets.UTF_8);

            for (MatchByDirectionReq matchByDirectionReq : redisList) {
                if (matchByDirectionReq != null) {
                    for (MatchDirectItem matchDirectItem : matchByDirectionReq.getDirectList()) {
                        if (matchDirectItem.getAccountName().equals(req.getAuthor()) || matchDirectItem.getAccountName().equals(req.getSource())) {
                            // 构建 uniqueKey
                            String uniqueKey = matchByDirectionReq.getPlanID() + "|" + matchDirectItem.getAccountName() + "|" + req.getSourceUrl();
                            // 对 uniqueKey 进行 MD5 加密
                            String uniqueKeyHash = DigestUtil.md5Hex16(uniqueKey);
                            // 将批量 SADD 操作加入 pipeline
                            connection.sAdd(redisKey, uniqueKeyHash.getBytes(StandardCharsets.UTF_8));
                        }
                    }
                }
            }
            return null; // 执行完 pipeline 后返回 null
        });
    }

    // 创建 PlanManagesItem 的方法
    private PlanManagesItem createPlanManagesItem(MatchByDirectionReq matchByDirectionReq, MatchDirectItem matchDirectItem) {
        PlanManagesItem planManagesItem = new PlanManagesItem();
        planManagesItem.setPlanManageId(matchByDirectionReq.getPlanID());
        planManagesItem.setAgencyId(matchByDirectionReq.getAgencyID());
        planManagesItem.setKeyword(matchDirectItem.getAccountName().trim());
        planManagesItem.setMonitorType(0);
        planManagesItem.setProjectType(0);
        planManagesItem.setIsWarning(0);
        planManagesItem.setOrganType(0);
        planManagesItem.setUrl(matchDirectItem.getUrl());
        return planManagesItem; // 返回构建的对象
    }

    @Override
    public List<MatchDistanceResp> matchByKeyword(List<MatchDistanceReq> reqList) {

        List<Long> dataIds = reqList.stream().map(MatchDistanceReq::getDataID).collect(Collectors.toList());
        // 处理单个请求的逻辑
        long start = System.currentTimeMillis();

        List<MatchDistanceResp> respList = reqList.stream()

                .map(req -> {
                    // 处理单个请求的逻辑
                    try {
                        return processSingleRequest(req);

                    }catch (Exception e){
                        log.error("关键字匹配逻辑出错：{},异常信息{}",JSONUtil.toJsonStr(reqList),e.getMessage());
                        e.printStackTrace();
                    }
                    return null;
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        if(!respList.isEmpty()){
            long end = System.currentTimeMillis();
            log.info("关键字一条消息匹配大小：{}，耗时：{}",reqList.size(),end-start);
            log.info("关键字匹配成功:{}",JSONUtil.toJsonStr(dataIds));

            // 匹配完成后发给推送队列
            String messageId = UUID.randomUUID().toString();
            Message pushDataMessage = MessageBuilder.withBody(JSONUtil.toJsonStr(respList).getBytes(StandardCharsets.UTF_8))
                    .setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN)
                    .setMessageId(messageId)  // 设置 MessageId
                    .setDeliveryMode(MessageDeliveryMode.PERSISTENT)
                    .build();
            CorrelationData correlationData = new CorrelationData(messageId);
            rabbitTemplate.send(RabbitMqCon.DIRECT_EXCHANGE, RabbitMqCon.PUSH_MATCHED_DATA_KEY + indexRotator.getNextIndex(), pushDataMessage, correlationData);

        }
        return respList;


    }

    private MatchDistanceResp processSingleRequest(MatchDistanceReq req) {

        MatchDistanceResp matchDistanceResp = new MatchDistanceResp();

        String text = req.getTitle() + " " + req.getContent() + " " + req.getImageContent();
        long start = System.currentTimeMillis();

        // 排除词
        Set<Long> excludedPlanIds = collectExcludedPlanIds(text);

        // 使用字典树进行匹配
        List<Emit> mainMatches = keywordIndex.match(text, "main");
        List<Emit> subMatches = keywordIndex.match(text, "sub");
        List<Emit> nextMatches = keywordIndex.match(text, "next");

        // 存储每组匹配的方案信息
        Map<Long, Set<String>> matchedPlans = new HashMap<>();


        // 处理主词匹配
        processMatches(mainMatches, matchedPlans, "keyword1", excludedPlanIds);

        // 处理副词匹配
        processMatches(subMatches, matchedPlans, "keyword2", excludedPlanIds);

        // 处理次词匹配
        processMatches(nextMatches, matchedPlans, "keyword3", excludedPlanIds);


        Map<Long, MatchByKeywordReq> keywordPlanMap = keywordIndex.keywordPlanMap;
        // 只保留 matchedPlans 中的键
        Map<Long, MatchByKeywordReq> filteredKeywordPlanMap = keywordPlanMap.entrySet().stream()
                .filter(entry -> matchedPlans.containsKey(entry.getKey())) // 仅保留 matchedPlans 中的键
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

        List<PlanManagesItem> planManages = new ArrayList<>();

        processPlanManages(req, text, planManages, filteredKeywordPlanMap);
        long end = System.currentTimeMillis();

        log.info("关键字单个数据匹配耗时：{}",end-start);
        if (!planManages.isEmpty()){
            buildResp(matchDistanceResp, req);
            matchDistanceResp.setPlanManages(planManages);
            return matchDistanceResp;
        }
        return null;

    }

    private void processPlanManages(MatchDistanceReq req, String text, List<PlanManagesItem> planManages,
                                    Map<Long, MatchByKeywordReq> planIdMapObj) {
        // 使用 CompletableFuture 处理有和没有忽略词的方案
        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> keywordHandler(req, text, planManages,
                planIdMapObj.values().stream().filter(m -> StrUtil.isBlank(m.getIgnoreKeyword())).collect(Collectors.toList())));

        CompletableFuture<Void> future2 =CompletableFuture.runAsync(() -> keywordHandler(req, text, planManages,
                planIdMapObj.values().stream().filter(m -> StrUtil.isNotBlank(m.getIgnoreKeyword())).collect(Collectors.toList())));

        try {
            // 使用 allOf 等待所有任务完成
            CompletableFuture<Void> allOf = CompletableFuture.allOf(future1, future2);
            // 等待任务完成
            allOf.get();
        } catch (InterruptedException | ExecutionException e) {
            Thread.currentThread().interrupt();
        }
    }

    private Set<Long> collectExcludedPlanIds(String text) {
        Set<Long> excludedPlanIds = new HashSet<>();
        List<Emit> excludeMatches = keywordIndex.match(text, "exclude");
        for (Emit excludeEmit : excludeMatches) {
            Set<String> planIds = keywordIndex.getPlansByKeyword("exclude", excludeEmit.getKeyword());
            excludedPlanIds.addAll(planIds.stream().map(Long::parseLong).collect(Collectors.toSet()));
        }
        return excludedPlanIds;
    }
    private void keywordHandler(MatchDistanceReq req, String text, List<PlanManagesItem> planManages,
                                List<MatchByKeywordReq> ignoreIsNullList) {

        String cleanText = text;
        for (MatchByKeywordReq keywordReq : ignoreIsNullList) {
            Integer monitorType = keywordReq.getMonitorType();
            String sp = monitorType == 0 ? "\\s+" : ";";
            List<KeywordItem> matchKeyword = keywordReq.getMatchKeyword();
            if(Objects.isNull(matchKeyword) || matchKeyword.isEmpty()){
                continue;
            }
            String ignoreKeyword = keywordReq.getIgnoreKeyword();
            if(StrUtil.isNotBlank(ignoreKeyword)){
                String[] split = ignoreKeyword.trim().split(sp);
                for (String s : split) {
                    cleanText = cleanText.replace(s,"———");
                }
            }
            String mediaType = keywordReq.getMediaType();
            if (StrUtil.isNotBlank(mediaType)) {
                String[] split = mediaType.split(",");
                String type = MediaTypeEnum.getDescByCode(req.getMediaType());
                if(!Arrays.asList(split).contains(type)){
                    // log.info("媒体类型不符合：{}",type);
                    continue;
                }
            }
            // 真正匹配到的关键字
            Set<String> matchKeywordList = new HashSet<>();
            // 遍历当前方案的多个组
            for (KeywordItem keywordItem : matchKeyword) {
                Set<String> keyword1Set = new HashSet<>();
                Set<String> keyword2Set = new HashSet<>();
                Set<String> keyword3Set = new HashSet<>();
                String[] keyword1s = keywordItem.getKeyword1().trim().split(sp);
                for (String keyword1 : keyword1s) {
                    if(cleanText.contains(keyword1)){
                        keyword1Set.add(keyword1);
                        break;
                    }
                }
                if(!keyword1Set.isEmpty()){
                    // 主词匹配上了 副词为空 添加主词
                    if(StrUtil.isBlank(keywordItem.getKeyword2())){
                        matchKeywordList.addAll(keyword1Set);
                        // 该方案匹配完毕
                        break;
                    }else {
                        // 副词不为空
                        String[] keyword2s = keywordItem.getKeyword2().trim().split(sp);
                        for (String keyword2 : keyword2s) {
                            if(cleanText.contains(keyword2)){
                                keyword2Set.add(keyword2);
                            }
                        }
                        if(!keyword2Set.isEmpty()){
                            // 副词匹配上了 次词为空 添加副词
                            if (StrUtil.isBlank(keywordItem.getKeyword3())) {
                                matchKeywordList.addAll(keyword1Set);
                                matchKeywordList.addAll(keyword2Set);
                                break;
                            }else {
                                // 次词不为空
                                String[] keyword3s = keywordItem.getKeyword3().trim().split(sp);
                                for (String keyword3 : keyword3s) {
                                    if(cleanText.contains(keyword3)){
                                        keyword3Set.add(keyword3);
                                    }
                                }
                                if(!keyword3Set.isEmpty()){
                                    matchKeywordList.addAll(keyword1Set);
                                    matchKeywordList.addAll(keyword2Set);
                                    // 次词匹配上了 添加次词
                                    matchKeywordList.addAll(keyword3Set);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            // 处理返回结果
            // 成功匹配到的关键字为空
            if(CollUtil.isEmpty(matchKeywordList)){
                continue;
            }
            PlanManagesItem item = new PlanManagesItem();
            item.setAgencyId(keywordReq.getAgencyID());
            item.setMonitorType(keywordReq.getMonitorType());

            item.setPlanManageId(keywordReq.getPlanID());
            Set<String> collect = matchKeywordList.stream().filter(StrUtil::isNotBlank).collect(Collectors.toSet());
            item.setKeyword(String.join(" ", collect)); // 用空格拼接关键词
//            String uniqueKey = item.getPlanManageId() + "|" + item.getKeyword() + "|" + req.getSourceUrl();
//            String uniqueKeyHash = DigestUtil.md5Hex(uniqueKey);
            planManages.add(item);


        }
    }


    /**
     *  @param matches 匹配结果
     * @param matchedPlans 方案id 映射 关键字集合
     * @param keywordType 关键字类型
     * @param excludedPlanIds 排除词id
     */
    private void processMatches(List<Emit> matches, Map<Long, Set<String>> matchedPlans, String keywordType,
                                Set<Long> excludedPlanIds) {
        for (Emit emit : matches) {
            String keyword = emit.getKeyword();
            // 获取该关键词对应的方案ID集合
            Set<String> planIds = keywordIndex.getPlansByKeyword(keywordType, keyword);
            for (String planId : planIds) {
                Long id = Long.parseLong(planId);
                // 跳过已排除的方案ID
                if (excludedPlanIds.contains(id)) {
                    continue;
                }
                // 同一个方案的主、副、次词都会添加进来
                matchedPlans.computeIfAbsent(id, k -> new HashSet<>()).add(keyword);

            }
        }
    }

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public BaseResp sendMockData(String routeKey, List<MatchDistanceReq> reqList) {

        String messageId = UUID.randomUUID().toString();
        Message message = MessageBuilder.withBody(JSONUtil.toJsonStr(reqList).getBytes(StandardCharsets.UTF_8))
                .setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN)
                .setMessageId(messageId)  // 设置 MessageId
                .setDeliveryMode(MessageDeliveryMode.PERSISTENT)
                .build();
        CorrelationData correlationData = new CorrelationData(messageId);
        rabbitTemplate.send(RabbitMqCon.DIRECT_EXCHANGE, routeKey, message, correlationData);
        return new BaseResp(200,null,"成功");
    }
}
